/**********************************************************************\

 Copyright 2012 Diggory Blake

 This file is part of klip-engine

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

\**********************************************************************/
#pragma once

#include <vector>
#include <string>
#include <sstream>
#include <map>
#include <functional>

#define INIT_N 15
#define INIT_ARG(p, n, z) p ## n = z
#define INIT_ARG2(p, n) p ## n
#define INIT_LIST(p, z)		INIT_ARG(p,0,z), INIT_ARG(p,1,z), INIT_ARG(p,2,z), \
							INIT_ARG(p,3,z), INIT_ARG(p,4,z), INIT_ARG(p,5,z), \
							INIT_ARG(p,6,z), INIT_ARG(p,7,z), INIT_ARG(p,8,z), \
							INIT_ARG(p,9,z), INIT_ARG(p,10,z), INIT_ARG(p,11,z), \
							INIT_ARG(p,12,z), INIT_ARG(p,13,z), INIT_ARG(p,14,z)
#define INIT_LIST2(p)		INIT_ARG2(p,0), INIT_ARG2(p,1), INIT_ARG2(p,2), \
							INIT_ARG2(p,3), INIT_ARG2(p,4), INIT_ARG2(p,5), \
							INIT_ARG2(p,6), INIT_ARG2(p,7), INIT_ARG2(p,8), \
							INIT_ARG2(p,9), INIT_ARG2(p,10), INIT_ARG2(p,11), \
							INIT_ARG2(p,12), INIT_ARG2(p,13), INIT_ARG2(p,14)
#define DEF_LIST(t, p)	t p ## s[] = { INIT_LIST2(p) }
#define GET_ARG(p, i)	((p ## s)[i])

#ifdef UNICODE
#define __T(x) L ## x
#define vstprintf (void)vswprintf
typedef wchar_t tchar;
namespace std {
	typedef wstring tstring;
	typedef wstringstream tstringstream;
	typedef wistringstream tistringstream;
	typedef wostringstream tostringstream;
	typedef wfstream tfstream;
	typedef wofstream tofstream;
	typedef wifstream tifstream;
	typedef wiostream tiostream;
	typedef wostream tostream;
	typedef wistream tistream;
}
#else
#define __T(x) x
#define vstprintf (void)vsnprintf
typedef char tchar;
namespace std {
	typedef string tstring;
	typedef stringstream tstringstream;
	typedef istringstream tistringstream;
	typedef ostringstream tostringstream;
	typedef fstream tfstream;
	typedef ofstream tofstream;
	typedef ifstream tifstream;
	typedef iostream tiostream;
	typedef ostream tostream;
	typedef istream tistream;
}
#endif
#define _T(x) __T(x)

#define FLAGS_ENUM(x) \
	inline x operator|(x a, x b) { return (x)((unsigned)a | (unsigned)b); } \
	inline x operator&(x a, x b) { return (x)((unsigned)a & (unsigned)b); } \
	inline x& operator|=(x& a, x b) { return (a = a | b); } \
	inline x& operator&=(x& a, x b) { return (a = a & b); } \
	inline x operator~(x a) { return (x)(~(unsigned)a); }

typedef void* kHandle;

template<typename T> class kCollection {
private:
	std::vector<T> _items;

public:
	template<typename Iter> kCollection(Iter begin, Iter end, size_t reserve = 25) {
		_items.reserve(reserve);
		for (Iter i = begin; i != end; i++) {
			T item = dynamic_cast<T>(*i);
			if (item)
				_items.push_back(item);
		}
	}
	typename std::vector<T>::iterator begin() {
		return _items.begin();
	}
	typename std::vector<T>::iterator end() {
		return _items.end();
	}
	typename std::vector<T>::iterator rbegin() {
		return _items.rbegin();
	}
	typename std::vector<T>::iterator rend() {
		return _items.rend();
	}
	typename std::vector<T>::const_iterator cbegin() const {
		return _items.cbegin();
	}
	typename std::vector<T>::const_iterator cend() const {
		return _items.cend();
	}
	typename std::vector<T>::const_iterator crbegin() const {
		return _items.crbegin();
	}
	typename std::vector<T>::const_iterator crend() const {
		return _items.crend();
	}
	typename std::vector<T>::size_type size() const {
		return _items.size();
	}
	bool empty() const {
		return _items.empty();
	}
};

template<typename T> class kDelegate {
private:
	std::map<kHandle, std::function<T>> _functions;
	kHandle _nextHandle;
public:
	inline std::function<T> _FType() {
		throw "DO NOT USE!";
	}

	inline kDelegate() {
		_nextHandle = (kHandle)1;
	}
	inline void operator()(std::function<void (std::function<T>)> lambda) const {
		for (auto i = _functions.begin(); i != _functions.end(); i++)
			lambda(i->second);
	}
	inline kHandle attach(std::function<T> f) {
		kHandle handle = _nextHandle;
		_nextHandle = (kHandle)((unsigned)_nextHandle + 1);
		_functions.insert(std::make_pair(handle, f));
		return handle;
	}
	inline void detach(kHandle handle) {
		_functions.erase(handle);
	}
	inline operator bool() const {
		return !_functions.empty();
	}
};

#define CALL_DELEGATE(x, ...) ((x)([&](decltype((x)._FType()) _f) { _f(__VA_ARGS__); }))
